package Hxw3DEngine.core.Resource.geometry
{
	import flash.display3D.Context3D;
	import flash.display3D.Context3DBufferUsage;
	import flash.display3D.IndexBuffer3D;
	import flash.utils.ByteArray;
	import flash.utils.Dictionary;
	import flash.utils.Endian;
	import Hxw3DEngine.asset.parsers.bson.format.VertexComponent;
	import Hxw3DEngine.asset.parsers.bson.format.VertexFormat;
	import Hxw3DEngine.asset.parsers.bson.vo.MeshVO;
	import Hxw3DEngine.asset.parsers.bson.vo.Stream;
	import Hxw3DEngine.core.Resource.IResourceAtom;
	import Hxw3DEngine.proxy.Stage3DProxy;
	import ao3s2.Flash3dLib.CModule;
	
	/**
	 * ...
	 * @author ...
	 */
	public class ResourceGeometry implements IResourceAtom
	{
		//==================== vb约定的寄存器索引===============
		
		/** 顶点 */
		public static const POSITION:int = 0;
		/** uv0,默认uv */
		public static const UV0:int = 1;
		/** uv1 */
		public static const UV1:int = 2;
		/** uv2 */
		public static const UV2:int = 3;
		/** uv3 */
		public static const UV3:int = 4;
		/** 法线 */
		public static const NORMAL:int = 5;
		/** 切线 */
		public static const TANGENT:int = 6;
		/** 颜色 */
		public static const RGBA:int = 7;
		/** 骨骼索引 */
		public static const SKIN_INDICES:int = 8;
		/** 权重 */
		public static const SKIN_WEIGHTS:int = 9;
		/** 骨骼权重0~1 */
		public static const BONE_0_1:int = 11;
		/** 骨骼权重2~3 */
		public static const BONE_2_3:int = 12;
		/** 颜色 */
		public static const RGB:int = 13;
		
		/** 自定义数据1 */
		public static const CUSTOM1:int = 14;
		/** 自定义数据2 */
		public static const CUSTOM2:int = 15;
		/** 自定义数据3 */
		public static const CUSTOM3:int = 16;
		/** 自定义数据4 */
		public static const CUSTOM4:int = 17;
		/** 数据格式数量 */
		public static const LENGTH:int = 18;
		
		private var _vbs:Vector.<VBObject> = new Vector.<VBObject>();
		private var _dictVbs:Dictionary = new Dictionary();
		private var _streamIb:Stream;
		private var _ib:IndexBuffer3D;
		private var _firstIndex:int;
		private var _numTriangles:int;
		private var _numVertices:int;
		private var _componentExist:Vector.<ComponentObject> = new Vector.<ComponentObject>(LENGTH);
		
		private var _bones_per_vertex:uint;
		private var _joints:int;            // 骨骼紧缩对照表的指针
		private var _numberOfJoints:uint;   // 骨骼紧缩对照表的数量
		
		// todo: ResourceGeometry(components:uint,...numberVectors)
		public function ResourceGeometry()
		{
			super();
		}
		
		public function useVertexBuffer(context3d:Context3D, componentWanted:Vector.<int>):void
		{
			var index:int = 0;
			for (var i:int = 0; i < componentWanted.length; i++)
			{
				var component:int = componentWanted[i];
				if (_componentExist[component] != null)
				{
					context3d.setVertexBufferAt(index, _componentExist[component].stream.vb, _componentExist[component].bufferOffset, _componentExist[component].format);
					index++;
				}
				else
				{
					throw(new Error("Shader wanted component[" + component + "],but it isn't exist in ResourceGeometry"));
				}
			}
		}
		
		public function get IndexBuffer():IndexBuffer3D
		{
			return _ib;
		}
		
		public function get firstIndex():int
		{
			return _firstIndex;
		}
		
		public function get numTriangles():int
		{
			return _numTriangles;
		}
		
		public function get numVertices():int
		{
			return _numVertices;
		}
		
		protected function addVertexStream(stream:Stream, numVertices:int, context3d:Context3D):void
		{
			var i:int;
			
			var vbo:VBObject = new VBObject();
			vbo.stream = stream;
			
			var componentIndex:Vector.<int> = new Vector.<int>();
			
			// todo:常用的format直接与 vbo.stream.components 对应
			
			// 根据 	vbo.stream.components  向	VertexFormat 添加 VertexComponent
			vbo.vertexFormat = new VertexFormat();
			for (i = 0; i < Stream.vertexComponents.length; i++)
			{
				if ((vbo.stream.components & (1 << i)) != 0)
				{
					vbo.vertexFormat.addComponent(Stream.vertexComponents[i]);
					componentIndex.push(i);
				}
			}
			// VertexFormat 知道每个 VertexComponent 的 FormatString,bufferOffset
			vbo.components = new Vector.<ComponentObject>(vbo.vertexFormat.numComponents);
			for (i = 0; i < vbo.vertexFormat.numComponents; i++)
			{
				var component:VertexComponent = vbo.vertexFormat.getComponent(i);
				vbo.components[i] = new ComponentObject();
				vbo.components[i].stream = vbo;
				vbo.components[i].format = component.nativeFormatString;
				vbo.components[i].bufferOffset = vbo.vertexFormat.getOffsetForComponent(component);
				_componentExist[componentIndex[i]] = vbo.components[i];
			}
			// VertexFormat 知道
			var staticDraw:Boolean = (vbo.stream.stream != null);
			vbo.vb = context3d.createVertexBuffer(numVertices, vbo.vertexFormat.numBytesPerVertex / 4, staticDraw ? Context3DBufferUsage.STATIC_DRAW : Context3DBufferUsage.DYNAMIC_DRAW);
			if (staticDraw)
			{
				vbo.vb.uploadFromByteArray(vbo.stream.stream, 0, 0, numVertices);
			}
			_vbs.push(vbo);
			_dictVbs[stream.components] = vbo;
		}
		
		protected function setIndexStream(stream:Stream, numIndices:int, context3d:Context3D):void
		{
			_streamIb = stream;
			_ib = context3d.createIndexBuffer(numIndices);
			_ib.uploadFromByteArray(_streamIb.stream, 0, 0, numIndices);
		}
		
		public function createFromVO(vo:Object):Boolean
		{
			var voMesh:MeshVO = vo as MeshVO;
			_numVertices = voMesh.vertices;
			_numTriangles = voMesh.indices;
			
			for (var i:int = 0; i < voMesh.streams.length; i++)
			{
				if (voMesh.streams[i].components == Stream.stream_indices)
				{
					setIndexStream(voMesh.streams[i], voMesh.indices, Stage3DProxy.context3d);
				}
				else
				{
					addVertexStream(voMesh.streams[i], voMesh.vertices, Stage3DProxy.context3d);
				}
			}
			
			_bones_per_vertex = voMesh.bones_per_vertex;
			if(voMesh.joints != null){
				_numberOfJoints = voMesh.joints.length;
				_joints = CModule.malloc(_numberOfJoints);
				CModule.writeBytes(_joints, _numberOfJoints, voMesh.joints);
			}
			
			return true;
		}
		
		public function dispose():void
		{
			_ib.dispose();
			for (var i:int = 0; i < _vbs.length; i++)
			{
				_vbs[i].vb.dispose();
			}
			if (_joints != 0) {
				CModule.free(_joints);
				_joints = 0;
			}
		}
		
		public function GetStreamIndexByFormat(components:int):VBObject
		{
			if (components in _dictVbs)
			{
				return _dictVbs[components];
			}
			return null;
		}
		
		public function UpdateStream(_targetStreamComponents:int, data:Vector.<Number>):void
		{
			var stream:VBObject = GetStreamIndexByFormat(_targetStreamComponents);
			if (stream != null)
			{
				stream.vb.uploadFromVector(data, 0, _numVertices);
			}
		}
		
		// 兼容直接创建接口
		public function createFormVectors(_numberVertices:uint, _vertexData:Vector.<Number>, _indexData:Vector.<uint>, _uvData:Vector.<Number> = null, _normalsData:Vector.<Number> = null, _tangentData:Vector.<Number> = null):void
		{
			var streams:Array = new Array();
			streams.push(Stream.fromVector(Stream.stream_positions, _vertexData));
			if (_uvData != null && _uvData.length > 0)
			{
				streams.push(Stream.fromVector(Stream.stream_uvs_1, _uvData));
			}
			if (_normalsData != null && _normalsData.length > 0)
			{
				streams.push(Stream.fromVector(Stream.stream_normals, _normalsData));
			}
			if (_tangentData != null && _tangentData.length > 0)
			{
				streams.push(Stream.fromVector(Stream.stream_tangents, _tangentData));
			}
			createFromStreams(_indexData, _numberVertices, streams);
		}
		
		public function createFromStreams(_indexData:Vector.<uint>, vertices:uint, _streams:Array):void
		{
			var i:int;
			var arrayStreams:Array = new Array();
			
			var baStreamIdx:ByteArray = new ByteArray();
			baStreamIdx.endian = Endian.LITTLE_ENDIAN;
			for (i = 0; i < _indexData.length; i++)
			{
				baStreamIdx.writeShort(_indexData[i] as int);
			}
			var streamIdx:Stream = new Stream({"components": Stream.stream_indices, "stream": {"data": baStreamIdx}});
			arrayStreams.push(streamIdx);
			
			for (i = 0; i < _streams.length; i++)
			{
				arrayStreams.push(_streams[i]);
			}
			var vo:Object = {"name": "unknown", "flags": 0, "material": 0, "streams": arrayStreams, "trangle_type": 0, "vertices": vertices, "bones_per_vertex": 0, "indices": _indexData.length};
			createFromVO(new MeshVO(vo));
		}
		public function get joints():int {
			return _joints;
		}

		public function get numberOfJoints():uint {
			return _numberOfJoints;
		}		
	}

}
import flash.display3D.VertexBuffer3D;
import Hxw3DEngine.asset.parsers.bson.format.VertexFormat;
import Hxw3DEngine.asset.parsers.bson.vo.Stream;

internal class ComponentObject
{
	public var stream:VBObject;
	public var bufferOffset:int;
	public var format:String;
}

internal class VBObject
{
	public var stream:Stream;
	public var vb:VertexBuffer3D;
	public var vertexFormat:VertexFormat;
	public var components:Vector.<ComponentObject>;
}
